﻿using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;

namespace MaterialTypeRecognition.Shell.AuthenticationServices
{
    public interface IJwtBearerService
    {
        string GetJwtToken(Action<ClaimBuilder> claimBuilder);
    }

    public class JwtBearerService : IJwtBearerService
    {
        private readonly IConfiguration _configuration;

        public JwtBearerService(IConfiguration configuration)
        {
            _configuration = configuration;
        }

        public string GetJwtToken(Action<ClaimBuilder> claimBuilder)
        {
            var jwtConfig = _configuration.GetSection("Jwt");

            //秘钥，就是标头，这里用 HmacSha256 算法，需要 256bit 的密钥。
            var securityKey = new SigningCredentials(
                new SymmetricSecurityKey(Encoding.ASCII.GetBytes(jwtConfig.GetValue<string>("Secret") ?? throw new InvalidOperationException())),
                                            SecurityAlgorithms.HmacSha256);

            // Claim，JwtRegisteredClaimNames中预定义了好多种默认的参数名，
            // 也可以使用 Guid 自己定义键名: new Claim("", Guid.NewGuid().ToString("D")),
            // ClaimTypes 也预定义了好多类型如 role、email、name。Role 用于赋予权限，不同的角色可以访问不同的接口，
            // 相当于有效载荷。
            ClaimBuilder builder = new ClaimBuilder();
            claimBuilder(builder);
            var claims = builder.GetClaims();
            claims.Add(new Claim(JwtRegisteredClaimNames.Iss, jwtConfig.GetValue<string>("Iss") ?? throw new InvalidOperationException()));
            claims.Add(new Claim(JwtRegisteredClaimNames.Aud, jwtConfig.GetValue<string>("Aud") ?? throw new InvalidOperationException()));

            SecurityToken securityToken = new JwtSecurityToken(
                signingCredentials: securityKey,
                expires: DateTime.Now.AddMinutes(3),
                claims: claims
            );

            // 生成 jwt 令牌。
            return new JwtSecurityTokenHandler().WriteToken(securityToken);
        }
    }
}
